前文我们提到过Service mesh分为control plane和data plane两个平面,data plane负责服务间的通信管理,而control plane负责策略配置收集监控数据鉴权等事项。严格意义来讲Istio只具有控制平面的功能,而在Istio中的data plane的功能是使用另外一个开源项目envoy来时实现的。这里为了不混淆,下文中的Istio只包括其control plane,而data plane使用envoy进行专指。前文已对Istio做完基本的介绍,按照正常的套路就应该介绍Istio的安装,但因为Istio的安装很简单,这里就不再赘述,大家可以移步https://istio.io/docs/setup/kubernetes/quick-start/。不过我们在安装的时候遇到几个问题可以在这里需要提一下:
- 安装istio时建议测试环境和没有外部业务通信的场景下建议不启动auth组件;
- 安装sidecar可以选择使用istioctl 命令行工具手动将sidecar注入到应用所在的pod,或者使用Istio Initializer每次在创建pod的时候自动将sidecar注入到业务容器所在那个pod里面
- 由于我们的k8s环境不支持loadbalance类型的TYPE,而istio-ingressgateway默认使用这个类型,导致在启动的时候pod都一直处于Pending状态,后来手动将类型改为nodeport,就可以正常启动。
Istio组件介绍
说完Istio的整体,那我们再看看看Istio的各个组件,先上一张官方文档里面的图:

图片来自https://istio.io/docs/concepts/what-is-istio/overview/
可以看到Istio在控制平面实际上有三个较为关键的组件。mixer主要有功能有:1、转发前的check(黑白名单、quota等)、转发后上报数据(监控)。这里说个题外话,目前mixer是整个Istio的一个性能瓶颈点之一,比如一次mesh服务间的网络通信至少需要两次和mixer进行RPC通信(调用前的check和调用后的report),所以mixer后续会是我们在定制化的时候需要做大量的优化,关于mixer这里暂时先按下不表,咱们后文详细说。第三个citadel主要适用于安全证书和鉴权方面。
pilot主要是负责配置通信控制策略并下发给envoy组件,那到底有哪些策略可以配置呢,主要就是提供服务发现与注册服务治理、动态的更新负载均衡的后端服务实例(定时监测某个服务是否存活)、更新route table(例如根据http的后缀进行匹配以确定具体发送给服务的某个版本)以及管理访问Service mesh内部业务的流入流量(ingress)和service mesh内部访问外部服务的流出的流量(egress)。
istio中的请求路由
istio的提供了所谓的服务版本的概念,通过将流量分发到同一服务的不同版本(或者不同的配置环境,例如:生产、测试等)就可以实现一个通用的流量路由控制场景,比如A/B测试等。当然也可以通过服务版本的概念实现负载均衡的分发策略。通过服务版本的模型,就可以实现业务与和他所依赖服务的解耦。
Istio的流量路由配置是通过提供一套API来进行路由规则的配置,目前有3个版本的API。在Istio0.7.X版本支持的事config.istio.io/v1alpha2版本。在最近的0.8.0版本开始支持config.istio.io/v1alpha3版本API。v1alpha3版本的API对v1alpha2中的API进行重构,也提供了更为灵活和强大的路由配置规则来实现在4层和7层网络的的流量控制和高级别服务治理如:熔断、降级、超时。同时也提供了一些通用的持续发布能力,例如金丝雀发布、灰度发布、A/B test
下来我会顺着官方的文档进行介绍,会加入一些对此的理解。
我们先上一个完整的路由配置策略,一下这个配置示例是实现将流入的流量100%的分发给一个叫做reviews的V1版本。
以上配置表明所有访问reviews服务(通过hosts字段进行配置)的流量都会被路由到reviews服务下面的V1版本的具体实例。那么关于reviews服务具有多少个路由子集(subset)是在对应的同名DestinationRule资源对象中进行配置的。
在subset配置中一般包含某个服务的一个或几个指定版本的服务实例,例如在使用kubernetes的deployment的资源对象进行部署的时候,这里的labels标签实际上就是和pod的label标签是等价的,例如在DestinationRule.subsets.labels=” version: v1”表示只有标注有version:v1这个label的pod会被导入请求流量。
在istio的v1alpha3版本API中有4个配置资源对象,分别是VirtualService, DestinationRule, ServiceEntry和Gateway。
virtualService配置资源对象
virtualService表示一个对service mesh中的服务如何进行路由的资源配置对象。对于一个服务的请求,virtualService可以根据其请求源和请求目标或者根据HTTP的URL路径或者报文头的字段匹配来决定将其路由到一个服务的不同版本,甚至另外一个完全不同的服务上。
目标服务
一个路由规则需要定义至少一个请求的最终目标服务,目标服务的配置就是在virtualService中的hosts字段,定义的目标服务也不需要和所映射的服务名保持名称一致,甚至在host中定义的目标服务后端不存在一个和名称对应的真实Service mesh 中的服务。在host中定义的服务名会被转义成kubernetes中的FQDN( fully qualified domain names),例如hosts中配置名为reviews的服务,就会被扩展成reviews.default.svc.cluster.local
根据请求源进行路由规则匹配
- 根据请求源服务来进行路由规则匹配,也就是说指定只有某个特定的服务来请求目标服务时,才会被路由规则匹配并且将请求转发给指定目标服务,例如以下配置:123456789101112apiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata:name: ratingsspec:hosts:- ratingshttp:- match:sourceLabels:app: reviews...
这里的sourcelaLabels属性对应的值就是限制请求源服务的,在k8s里面就是需要请求源服务被设置了 app: reviews这个值
2、 限制源服务除了指定具体的服务明以外,还可以更细粒度也就是服务的版本,比如下面配置表示,只有reviews这个mesh服务的V2版本才能匹配成功。
3、 还可以通过请求的HTTP报文头里面的某个属性字段来进行匹配,甚至可以支持正则表达式和一次设置多个表达式。这里就不再一一举例,详情请各位看官参照文档
根据服务的版本分发流量
每个路由规则都会定义一个或多个被规则引入流量的目标服务,目标服务对应会有版本,版本号是通过label标签来进行标识的,若一个服务的某一个版本有多个注册实例,则按照设置好的轮询算法或者使用默认的round-robin算法进行负责均衡,负载均衡的流量比例通过weight字段来标识,例如下列配置demo
超时和重试
在Istio中的默认超时时间是15s,但是可以通过定义timeout属性来重写超时时间,如下配置:
重试次数也可以通过配置实现,配置的时候需要给定两个值,重试的最大重试次数和每次重试的超时时间,如下配置:
在请求中注入错误
在Istio中注入的错误类型可以分为两种类型:超时和终止。以下配置表示有10%的访问ratings服务V1版本的请求将会有至少5s的延时。
在另外一种注入错误:终止。可以用来提起终止一个请求,例如以下配置表示有10%的访问rating服务V1版本的请求将会返回HTTP400错误
超时与提前终止请求可以同时使用,以下配置将使所有请求都延迟5s,并且其中的10%直接返回400错误
HTTP路由规则的优先级顺序
当对于目标服务有多个规则是,则按照他们在virtualService中出现的顺序进行优先级排序,在编写请求路由时,有一个路由编写规范就是match匹配请求源和请求报文头放到最前面以设置最高优先级,然后再单独提供基于权重但是没有匹配表达式的weight规则来匹配剩余的请求流量。例如对于下面的配置中的virtualService有两条对应的目标规则。指定了所有的请求如果报文头中包含Foo字段并且其值为bar则将流量发送到V2版本实例。剩余的请求流量将路由至V1版本实例
Destination Rules配置资源对象
Destination Rules配置了一系列的规则用于在virtualService已经匹配成功后的后续路由动作,主要用于描述熔断器、负载均衡策略,TLS设置等等相关配置。destinationRules会定义好一个目标服务对应的的子集(subset)。这个subset将根据VirtualService匹配后的请求路由到制定的某个服务的具体版本上。
host层面已经指定了默认的负载均衡策略,但在V2服务版本的配置重写了默认的负载均衡策略,这样当V2版本有多个实例时,则可以根据这个重写的规则来确定具体的负载均衡分发策略
熔断器
一个简单的熔断器配置可以根据连接和请求的流量最大值进行限流,例如以下配置中,在DestinationRule设置了reviews服务最大可以建立100个连接
Service Entries配置资源对象
ServiceEntry允许将外部服务注册到istio内部维护的注册表里,这个主要就是为了service mesh内部访问外部的服务。例如以下配置就是将在*.abc.com域名下的外部服务声明为一个服务,共service mesh内部访问
ServiceEntry分为内部和外部两种类型,内部服务和其他service mesh服务没有什么区别,只是为了显示的声明将某个服务注册到service mesh中。例如将某个私有云内部部署在虚拟机上面的业务显式地添加到基于k8s的service mesh服务当中。外部类型就主要表示外部服务,此类外部服务无法使用TLS进行通信,并且很多策略的控制都是在客户端进行的,而不是像在内部服务请求一样在服务端执行策略。
gateway配置资源对象
gateway为HTTP/TCP流量配置负载均衡器,最常见的是在service meshb边缘运行,以启用控制流入service mesh的流量。与Kubernetes Ingress不同,Istio Gateway仅配置L4-L6功能(例如,要暴露的端口,TLS配置)。用户可以使用标准的Istio规则来控制HTTP请求以及通过将VirtualService绑定到网关而进入网关的TCP流量。例如,以下简单网关配置负载均衡器,以允许主机bookinfo.com的外部https流量进入service mesh:
如果要映射路由到后端的具体某个服务还需要配置相应的路由,virtualService必须使用配置gateway定义的为同一host配置VirtualService: